#include<iostream>
#include <mutex>
using namespace std;

template<class T>
class SharedPtr
{
public:
	SharedPtr(T* ptr = nullptr) :_ptr(ptr), _count(new int(1)), _mtx(new mutex)
	{}
	SharedPtr(const SharedPtr& sp)
	{
		_count = sp._count;
		_ptr = sp._ptr;
		_mtx = sp._mtx;
		AddCount();
	}
	~SharedPtr()
	{
		Release();
	}
	SharedPtr<T> operator=(const SharedPtr<T>& sp)
	{
		if (sp._ptr != _ptr)
		{
			Release();
			_ptr = sp._ptr;
			_mtx = sp._mtx;
			_count = sp._count;
		}
		AddCount();
		return this;
	}
	void AddCount()
	{
		_mtx->lock();
		(*_count)++;
		_mtx->unlock();
	}
	void Release()
	{
		_mtx->lock();
		if (--(*_count) == 0)
		{
			delete _ptr;
			delete _mtx;
			delete _count;
		}
		_mtx->unlock();
	}
	T& operator*()
	{
		return *_ptr;
	}
	T* operator->()
	{
		return _ptr;
	}

public:
	T* _ptr;
	int* _count;
	mutex* _mtx;
};

int main()
{
	int a = 10;
	SharedPtr<int> sp1(&a);
	SharedPtr<int> sp2(sp1);
	SharedPtr<int> sp3 = sp1;
	cout << *sp1 << " " << *sp2 << " " << *sp3 << endl;
	cout << (*sp1._count) << endl;
	return 0;
}